using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Reflection;

namespace NBusiness.Data
{
    public class ObjectDataReader<T> : IDataReader
    {
        private int _readIndex = -1;
        private bool _isClosed = false;
        private T[] _data;
        PropertyInfo[] _properties;
        
        public ObjectDataReader(params T[] data)
        {
            _data = data;
            _properties = typeof(T).GetProperties();
        }

        #region IDataReader Members

        
        public void Close()
        {
            _data = null;
            _isClosed = true;
        }

        public int Depth
        {
            get 
            {
                return _data.Length;
            }
        }

        public DataTable GetSchemaTable()
        {
            DataTable table = new DataTable();
            foreach (PropertyInfo pi in _properties)
            {
                table.Columns.Add(pi.Name, pi.PropertyType);
            }
            foreach(T t in _data)
            {
                table.Rows.Add(t);
            }
            return table;
        }

        public bool IsClosed
        {
            get { return _isClosed; }
        }

        public bool NextResult()
        {
            return _readIndex + 1 < _data.Length;
        }

        public bool Read()
        {
            _readIndex++;
            return _readIndex < _data.Length && _readIndex > -1;
        }

        public int RecordsAffected
        {
            get { return _data.Length; }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Close();
        }

        #endregion

        #region IDataRecord Members

        public int FieldCount
        {
            get { return _properties.Length; }
        }

        public bool GetBoolean(int i)
        {
            return (bool)GetValue(i);
        }

        public byte GetByte(int i)
        {
            return (byte)GetValue(i);
        }

        public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
        {
            byte[] bytes = (byte[])GetValue(i);
            Array.Copy(bytes, fieldOffset, buffer, bufferoffset, length);
            return buffer.Length;
        }

        public char GetChar(int i)
        {
            return (char)GetValue(i);
        }

        public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
        {
            string chars = GetString(i);
            chars.CopyTo((int)fieldoffset, buffer, bufferoffset, length);
            return buffer.Length;
        }

        public IDataReader GetData(int i)
        {
            return null;
        }

        public string GetDataTypeName(int i)
        {
            return _properties[i].PropertyType.Name;
        }

        public DateTime GetDateTime(int i)
        {
            return (DateTime)GetValue(i);
        }

        public decimal GetDecimal(int i)
        {
            return (decimal)GetValue(i);
        }

        public double GetDouble(int i)
        {
            return (double)GetValue(i);
        }

        public Type GetFieldType(int i)
        {
            return _properties[i].PropertyType;
        }

        public float GetFloat(int i)
        {
            return (float)GetValue(i);
        }

        public Guid GetGuid(int i)
        {
            return (Guid)GetValue(i);
        }

        public short GetInt16(int i)
        {
            return (short)GetValue(i);
        }

        public int GetInt32(int i)
        {
            return (int)GetValue(i);
        }

        public long GetInt64(int i)
        {
            return (long)GetValue(i);
        }

        public string GetName(int i)
        {
            return _properties[i].Name;
        }

        public int GetOrdinal(string name)
        {
            int ordinal = -1;
            for (int x = 0; x < _properties.Length; x++)
            {
                if (_properties[x].Name == name)
                {
                    ordinal = x;
                    break;
                }
            }
            return ordinal;
        }

        public string GetString(int i)
        {
            return (string)GetValue(i);
        }

        public object GetValue(int i)
        {
            T t = _data[_readIndex];
            PropertyInfo p = _properties[i];
            return p.GetValue(t, null);
        }

        public int GetValues(object[] values)
        {
            for(int x=0;x<_properties.Length;x++)
            {
                values[x] = _properties[x].GetValue(_data[_readIndex], null);
            }
            return _properties.Length;
        }

        public bool IsDBNull(int i)
        {
            return false; //No way to know without knowing if the column is nullable.
        }

        public object this[string name]
        {
            get 
            {
                int i = this.GetOrdinal(name);
                return GetValue(i);
            }
        }

        public object this[int i]
        {
            get 
            {
                return GetValue(i);
            }
        }

        #endregion
    }
}
